#include "server.h"  

//RabinServer
RabinServer::RabinServer(MessageCollection* msgs, int32_t prt) {
    colMsg = msgs;
    port = prt;
	socket = new Socket();
}

RabinServer::~RabinServer() {
    delete socket;
    delete colMsg;
}
  
CipherMessageCollection* RabinServer::prepareMessage(const RabinServerKey* key, const MessageCollection* x, const CipherMessage* chint) {
	//
	uint32_t colSize = x->getSize();
	int32_t *rawTmp = new int32_t[colSize];	
	for(uint32_t i = 0;i < colSize;i++){		
		CipherMessage *cmTmp = key->encrypt(colMsg->get(i),x->get(i),chint);
		rawTmp[i] = cmTmp->getRaw();
	}	
	return new CipherMessageCollection(new MessageCollection(colSize,rawTmp));
}

void RabinServer::handleOnce() {
    // 1-2 OT Step 2
	RabinServerKey* key = RabinServerKey::fromRandom(colMsg->getSize());	                //choose proper key according to the number of message
	
	socket->Send(key->getPublic()->getSerialization());
	//cout<<"Step2:send public key n "<<(key->getPublic())->getN()<<" key e "<<(key->getPublic())->getE()<<endl;	
    // 1-2 OT Step 3
    MessageCollection* colTmp = MessageCollection::fromRandom(colMsg->getSize());
	socket->Send(colTmp->getSerialization());
	/*cout<<"Step3:send MessageCollection:"<<endl;	
	for(uint32_t i = 0;i < colTmp->getSize();i++) {
		cout<<colTmp->get(i)->getData()<<endl;
	}
	*/
    // colTmp: x_0, x_1,     
    // 1-2 OT Step 5
    CipherMessage* chint = CipherMessage::fromRaw(socket->Receive());
	//cout<<"Step5:recieve chint "<<chint->getRaw()<<endl;
    // 1-2 OT Step 6 & Step 7
    CipherMessageCollection* colCipher = prepareMessage(key, colTmp, chint);	
    // colTmp now: m_0', m_1', ...
	socket->Send(colCipher->getSerialization());	
	/*cout<<"Step6&7:send MessageCollection:"<<endl;	
	for(uint32_t i = 0;i < colCipher->getSize();i++) {
		cout<<colCipher->get(i)->getRaw()<<endl;
	}*/
	
    delete colCipher;
    delete chint;
    delete colTmp;
    delete key;	
}

void RabinServer::run() {
	for (;;) {
		socket->Wait(port);	
		handleOnce();
	}
}
